package com.cx.auth.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Array;
import java.net.URL;
import java.net.URLDecoder;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * @author huangzz
 * 通用对象操作帮助类，或者你可以叫它是 one piece ????
 */
public final class Op {
    private static final Pattern PATTERN_NUMERIC = Pattern.compile("^0$|^\\-?[1-9]+[0-9]*$");
    private static final Pattern PATTERN_EMAIL_ADDR = Pattern.compile("^[a-z0-9_\\-]+(\\.[_a-z0-9\\-]+)*@([_a-z0-9\\-]+\\.)+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel)$");
    private static final Pattern PATTERN_IP_ADDR = Pattern.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$");
    private static final Pattern PATTERN_LINK = Pattern.compile("<a[^>]*href=\\\"[^\\s\\\"]+\\\"[^>]*>[^<]*<\\/a>");
    private static final Pattern PATTERN_HTTP_URL = Pattern.compile("^(https?:\\/\\/)?([a-z]([a-z0-9\\-]*\\.)+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel)|(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))(\\/[a-z0-9_\\-\\.~]+)*(\\/([a-z0-9_\\-\\.]*)(\\?[a-z0-9+_\\-\\.%=&amp;]*)?)?(#[a-z][a-z0-9_]*)?$");
    private static final Pattern PATTERN_XML_ESCAPES = Pattern.compile(".*[&|\"|\'|<|>].*");

    private static final String[] SHORT_DATE_PATTERN = {"yyyy-MM-dd", "yyyy/MM/dd", "yyyy\\MM\\dd", "yyyyMMdd"};
    private static final String[] LONG_DATE_PATTERN = {"yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss", "yyyy\\MM\\dd HH:mm:ss", "yyyyMMddHHmmss"};
    private static final String[] LONG_DATE_PATTERN_WITH_MILSEC = {"yyyy-MM-dd HH:mm:ss.SSS", "yyyy/MM/dd HH:mm:ss.SSS", "yyyy\\MM\\dd HH:mm:ss.SSS", "yyyyMMddHHmmssSSS"};
    private static String STRING_PLACE_HOLDER = "{}";
    private static final Map<String, Locale> AVAILABLE_LOCALES = new HashMap<String, Locale>();
    private static final char[][] XML_ESCAPE_CHARS = new char[63][];

    private Op() {
    }

    /**
     * 空字符串
     */
    public static final String EMPTY_STRING = "";
    /**
     * 默认字符编码
     */
    public static final String DEFAULT_ENCODING = "UTF-8";
    /**
     * 当前操作系统平台
     */
    public static final String OS_PLATFORM = getOSName();
    /**
     * 当前操作系统平台是否为 Windows
     */
    public static final boolean IS_WINDOWS_PLATFORM = isWindowsPlatform();
    /**
     * 当前操作系统平台的换行符
     */
    public static final String NEWLINE_CHAR = IS_WINDOWS_PLATFORM ? "\r\n" : "\n";

    static {
        Locale[] locales = Locale.getAvailableLocales();
        for (Locale locale : locales) {
            AVAILABLE_LOCALES.put(locale.toString(), locale);
        }
        XML_ESCAPE_CHARS[38] = "&amp;".toCharArray();
        XML_ESCAPE_CHARS[60] = "&lt;".toCharArray();
        XML_ESCAPE_CHARS[62] = "&gt;".toCharArray();
        XML_ESCAPE_CHARS[34] = "&quot;".toCharArray();
        XML_ESCAPE_CHARS[39] = "&apos;".toCharArray();
    }

    /**
     * 获取系统支持的所有 {@link Locale}
     */
    public final static Map<String, Locale> getAvailableLocales() {
        return AVAILABLE_LOCALES;
    }

    /**
     * 获取系统支持的指定名称的 {@link Locale}
     */
    public final static Locale getAvailableLocale(String locale) {
        return AVAILABLE_LOCALES.get(locale);
    }

    public static boolean isEmpty(Object source) {
        if (source == null) {
            return true;
        }
        boolean flag = false;
        if (source instanceof String) {
            flag = StringUtils.isBlank((String) source);
        } else if (source instanceof Collection) {
            flag = ((Collection) source).isEmpty();
        } else if (source instanceof Map) {
            flag = ((Map) source).isEmpty();
        } else {
            try {
                flag = ArrayUtils.getLength(source) == 0;
            } catch (IllegalArgumentException e) {
                flag = false;
            }
        }
        return flag;
    }

    public static boolean isNotEmpty(Object source) {
        return !isEmpty(source);
    }


    /**
     * 检查字符串为 null 、空字符串或只包含空格
     */
    public final static boolean isTrimStrEmpty(String str) {
        String trim = safeTrimString(str);
        return isEmpty(trim);
    }

    /**
     * 把参数 str 转换为安全字符串：如果 str = null，则把它转换为空字符串
     */
    public final static String safeString(String str) {
        if (str == null) {
            str = "";
        }
        return str;
    }

    /**
     * 把参数 obj 转换为安全字符串：如果 obj = null，则把它转换为空字符串
     */
    public final static String safeString(Object obj) {
        if (obj == null) {
            return "";
        }
        return obj.toString();
    }

    /**
     * 把参数 str 转换为安全字符串并执行去除前后空格：如果 str = null，则把它转换为空字符串
     */
    public final static String safeTrimString(String str) {
        return safeString(str).trim();
    }


    /**
     * 检查字符串是否符合整数格式
     */
    public final static boolean isStrNumeric(String str) {
        return PATTERN_NUMERIC.matcher(str).matches();
    }

    /**
     * 检查字符串是否符合电子邮件格式
     */
    public final static boolean isStrEmailAddress(String str) {
        return PATTERN_EMAIL_ADDR.matcher(str).matches();
    }

    /**
     * 检查字符串是否符合 IP 地址格式
     */
    public final static boolean isIp(String str) {
        return PATTERN_IP_ADDR.matcher(str).matches();
    }

    /**
     * 检查字符串是否符合 HTML 超链接元素格式
     */
    public final static boolean isStrLink(String str) {
        return PATTERN_LINK.matcher(str).matches();
    }

    /**
     * 检查字符串是否符合 URL 格式
     */
    public final static boolean isStrURL(String str) {
        return PATTERN_HTTP_URL.matcher(str).matches();
    }

    /**
     * 置换常见的 XML 特殊字符
     */
    public final static String escapeXML(String str) {
        if (!PATTERN_XML_ESCAPES.matcher(str).matches()) {
            return str;
        }

        char[] src = str.toCharArray();
        StringBuilder sb = new StringBuilder(src.length);

        for (char c : src) {
            if (c > '>' || c < '"') {
                sb.append(c);
            } else {
                char[] dest = XML_ESCAPE_CHARS[c];

                if (dest == null) {
                    sb.append(c);
                } else {
                    sb.append(dest);
                }
            }
        }

        return sb.toString();
    }

    /**
     * 屏蔽正则表达式的转义字符（但不屏蔽 ignores 参数中包含的字符）
     */
    public static final String escapeRegexChars(String str, char... ignores) {
        final char ESCAPE_CHAR = '\\';
        final char[] REGEX_CHARS = {'.', ',', '?', '+', '-', '*', '^', '$', '|', '&', '{', '}', '[', ']', '(', ')', '\\'};

        char[] regex_chars = REGEX_CHARS;

        if (ignores.length > 0) {
            Set<Character> cs = new HashSet<Character>(REGEX_CHARS.length);

            for (int i = 0; i < REGEX_CHARS.length; i++) {
                cs.add(REGEX_CHARS[i]);
            }
            for (int i = 0; i < ignores.length; i++) {
                cs.remove(ignores[i]);
            }
            int i = 0;
            regex_chars = new char[cs.size()];
            Iterator<Character> it = cs.iterator();

            while (it.hasNext()) {
                regex_chars[i++] = it.next();
            }
        }

        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);

            for (int j = 0; j < regex_chars.length; j++) {
                if (c == regex_chars[j]) {
                    sb.append(ESCAPE_CHAR);
                    break;
                }
            }

            sb.append(c);
        }

        return sb.toString();
    }

//    /**
//     * 符分割字符串（分割符：" \t\n\r\f,;"）
//     */
//    public final static String[] splitStr(String str) {
//        return splitStr(str, " \t\n\r\f,;");
//    }
//
//    /**
//     * 符分割字符串（分割符：由 delim 参数指定）
//     */
//    public final static String[] splitStr(String str, String delim) {
//        StringTokenizer st = new StringTokenizer(str, delim);
//        String[] array = new String[st.countTokens()];
//
//        int i = 0;
//        while (st.hasMoreTokens()) {
//            array[i++] = st.nextToken();
//        }
//        return array;
//    }

    /**
     * 调用 {@linkplain Thread#sleep(long)} 方法使当前线程睡眠 period 毫秒 <br>
     * <p>
     * 如果 {@linkplain Thread#sleep(long)} 方法被中断则返回 false
     */
    public final static boolean waitFor(long period) {
        if (period > 0) {
            try {
                Thread.sleep(period);
            } catch (Exception e) {
                return false;
            }
        } else {
            Thread.yield();
        }
        return true;
    }

    /**
     * 调用 {@linkplain Thread#sleep(long)} 方法使当前线程睡眠 period 个 unit 时间单元 <br>
     * <p>
     * 如果 {@linkplain Thread#sleep(long)} 方法被中断则返回 false
     */
    public final static boolean waitFor(long period, TimeUnit unit) {
        return waitFor(unit.toMillis(period));
    }

    /**
     * String -> Integer，如果转换不成功则返回 null
     */
    public final static Integer str2Int(String s) {
        Integer returnVal;
        try {
            returnVal = Integer.decode(safeTrimString(s));
        } catch (Exception e) {
            returnVal = null;
        }
        return returnVal;
    }

    /**
     * String -> int，如果转换不成功则返回默认值 d
     */
    public final static int str2Int(String s, int d) {
        int returnVal;
        try {
            returnVal = Integer.parseInt(safeTrimString(s));
        } catch (Exception e) {
            returnVal = d;
        }
        return returnVal;
    }


    /**
     * String -> Short，如果转换不成功则返回 null
     */
    public final static Short str2Short(String s) {
        Short returnVal;
        try {
            returnVal = Short.decode(safeTrimString(s));
        } catch (Exception e) {
            returnVal = null;
        }
        return returnVal;
    }

    /**
     * String -> short，如果转换不成功则返回默认值 d
     */
    public final static short str2Short(String s, short d) {
        short returnVal;
        try {
            returnVal = Short.parseShort(safeTrimString(s));
        } catch (Exception e) {
            returnVal = d;
        }
        return returnVal;
    }


    /**
     * String -> Long，如果转换不成功则返回 null
     */
    public final static Long str2Long(String s) {
        Long returnVal;
        try {
            returnVal = Long.decode(safeTrimString(s));
        } catch (Exception e) {
            returnVal = null;
        }
        return returnVal;
    }

    /**
     * String -> long，如果转换不成功则返回默认值 d
     */
    public final static long str2Long(String s, long d) {
        long returnVal;
        try {
            returnVal = Long.parseLong(safeTrimString(s));
        } catch (Exception e) {
            returnVal = d;
        }
        return returnVal;
    }

    /**
     * String -> Float，如果转换不成功则返回 null
     */
    public final static Float str2Float(String s) {
        Float returnVal;
        try {
            returnVal = Float.valueOf(safeTrimString(s));
        } catch (Exception e) {
            returnVal = null;
        }
        return returnVal;
    }

    /**
     * String -> float，如果转换不成功则返回默认值 d
     */
    public final static float str2Float(String s, float d) {
        float returnVal;
        try {
            returnVal = Float.parseFloat(safeTrimString(s));
        } catch (Exception e) {
            returnVal = d;
        }
        return returnVal;
    }


    /**
     * String -> Double，如果转换不成功则返回 null
     */
    public final static Double str2Double(String s) {
        Double returnVal;
        try {
            returnVal = Double.valueOf(safeTrimString(s));
        } catch (Exception e) {
            returnVal = null;
        }
        return returnVal;
    }

    /**
     * String -> double，如果转换不成功则返回默认值 d
     */
    public final static double str2Double(String s, double d) {
        double returnVal;
        try {
            returnVal = Double.parseDouble(safeTrimString(s));
        } catch (Exception e) {
            returnVal = d;
        }
        return returnVal;
    }


    /**
     * String -> Byte，如果转换不成功则返回 null
     */
    public final static Byte str2Byte(String s) {
        Byte returnVal;
        try {
            returnVal = Byte.decode(safeTrimString(s));
        } catch (Exception e) {
            returnVal = null;
        }
        return returnVal;
    }

    /**
     * String -> byte，如果转换不成功则返回默认值 d
     */
    public final static byte str2Byte(String s, byte d) {
        byte returnVal;
        try {
            returnVal = Byte.parseByte(safeTrimString(s));
        } catch (Exception e) {
            returnVal = d;
        }
        return returnVal;
    }


    /**
     * String -> Character，如果转换不成功则返回 null
     */
    public final static Character str2Char(String s) {
        Character returnVal;
        try {
            returnVal = safeTrimString(s).charAt(0);
        } catch (Exception e) {
            returnVal = null;
        }
        return returnVal;
    }

    /**
     * String -> char，如果转换不成功则返回默认值 d
     */
    public final static char str2Char(String s, char d) {
        char returnVal;
        try {
            returnVal = safeTrimString(s).charAt(0);
        } catch (Exception e) {
            returnVal = d;
        }
        return returnVal;
    }


    /**
     * String -> Boolean，如果转换不成功则返回 null
     */
    public final static Boolean str2Boolean(String s) {
        return str2Boolean(s, null);
    }

    /**
     * String -> boolean，如果转换不成功则返回默认值 d
     */
    public final static Boolean str2Boolean(String s, Boolean d) {
        s = safeTrimString(s);
        try {
            Boolean result = BooleanUtils.toBoolean(s);
            return result == null ? d : result;
        } catch (Exception e) {
            return d;
        }
    }


    /**
     * String -> java.util.Date， str 的格式由 format  定义
     */
    public final static Date str2Date(String str, String format) {
        Date date = null;

        try {
            DateFormat df = new SimpleDateFormat(format);
            date = df.parse(safeTrimString(str));
        } catch (Exception e) {

        }

        return date;
    }

    /**
     * String -> java.util.Date，由函数自身判断 str 的格式
     */
    public final static Date str2Date(String str) {
        Date date = null;

        try {
            final char SEPARATOR = '-';
            final String[] PATTERN = {"yyyy", "MM", "dd", "HH", "mm", "ss", "SSS"};
            String[] values = safeTrimString(str).split("\\D");
            String[] element = new String[values.length];

            int length = 0;
            for (String e : values) {
                e = e.trim();
                if (e.length() != 0) {
                    element[length++] = e;
                    if (length == PATTERN.length) {
                        break;
                    }
                }
            }

            if (length > 0) {
                StringBuilder value = new StringBuilder();

                if (length > 1) {
                    for (int i = 0; i < length; ++i) {
                        value.append(element[i]);
                        value.append(SEPARATOR);
                    }
                } else {
                    String src = element[0];
                    int remain = src.length();
                    int pos = 0;
                    int i = 0;

                    for (i = 0; remain > 0 && i < PATTERN.length; ++i) {
                        int p_length = PATTERN[i].length();
                        int v_length = Math.min(p_length, remain);
                        String v = src.substring(pos, pos + v_length);
                        pos += v_length;
                        remain -= v_length;

                        value.append(v);
                        value.append(SEPARATOR);
                    }

                    length = i;
                }

                StringBuilder format = new StringBuilder();

                for (int i = 0; i < length; ++i) {
                    format.append(PATTERN[i]);
                    format.append(SEPARATOR);
                }

                date = str2Date(value.toString(), format.toString());
            }
        } catch (Exception e) {

        }

        return date;
    }

    /**
     * String -> java.util.Date，由 Patterns 指定可能的日期格式
     */
    public final static Date str2Date(String str, String[] Patterns) {
        Date date = null;

        for (int i = 0; i < Patterns.length; ++i) {
            date = str2Date(str, Patterns[i]);

            if (date != null) {
                break;
            }
        }

        return date;
    }

    /**
     * String -> java.util.Date，由 GeneralHelper.SHORT_DATE_PATTERN 指定可能的日期格式
     */
    public final static Date str2ShortDate(String str) {
        return str2Date(str, SHORT_DATE_PATTERN);
    }

    /**
     * String -> java.util.Date，由 GeneralHelper.LONG_DATE_PATTERN 指定可能的日期格式
     */
    public final static Date str2LongDate(String str) {
        return str2Date(str, LONG_DATE_PATTERN);
    }

    /**
     * String -> java.util.Date，由 GeneralHelper.LONG_DATE_PATTERN_WITH_MILSEC 指定可能的日期格式
     */
    public final static Date str2LongDateWithMilliSecond(String str) {
        return str2Date(str, LONG_DATE_PATTERN_WITH_MILSEC);
    }

    /**
     * 类型转换处理器接口
     */
    public static interface TypeHandler<T> {
        T handle(String v);
    }

    /**
     * String -> Any，字符串转换为 8 种基础数据类型、及其包装类 {@link Date}、 或 {@link String}
     *
     * @param type : 目标类型的 {@link Class} 对象
     * @param v    : 要转换的字符串
     * @return : 转换结果，如果转换不成功返回 null
     * @throws : 如果目标类型不支持抛出 {@link IllegalArgumentException}
     */
    public static final <T> T str2Object(Class<T> type, String v) {
        return str2Object(type, v, null);
    }

    /**
     * String -> Any，如果 handler 为 null 则把字符串转换为 8 种基础数据类型、及其包装类、 {@link Date} 或 {@link String}，
     * 如果 handler 不为 null 则由 handler 执行转换
     *
     * @param type    : 目标类型的 {@link Class} 对象
     * @param v       : 要转换的字符串
     * @param handler : 类型转换处理器
     * @return : 转换结果，如果转换不成功返回 null
     * @throws : 如果目标类型不支持抛出 {@link IllegalArgumentException}
     */
    @SuppressWarnings("unchecked")
    public static final <T> T str2Object(Class<T> type, String v, TypeHandler<T> handler) {
        //fixme 需要重构
        Object param = null;

        if (handler != null) {
            return handler.handle(v);
        }
        if (type == String.class) {
            param = safeTrimString(v);
        } else if (type == int.class) {
            param = str2Int(v, 0);
        } else if (type == long.class) {
            param = str2Long(v, 0L);
        } else if (type == byte.class) {
            param = str2Byte(v, (byte) 0);
        } else if (type == char.class) {
            param = str2Char(v, Character.MIN_VALUE);
        } else if (type == float.class) {
            param = str2Float(v, 0F);
        } else if (type == double.class) {
            param = str2Double(v, 0D);
        } else if (type == short.class) {
            param = str2Short(v, (short) 0);
        } else if (type == boolean.class) {
            param = str2Boolean(v, Boolean.FALSE);
        } else if (type == Integer.class) {
            param = str2Int(v);
        } else if (type == Long.class) {
            param = str2Long(v);
        } else if (type == Byte.class) {
            param = str2Byte(v);
        } else if (type == Character.class) {
            param = str2Char(v);
        } else if (type == Float.class) {
            param = str2Float(v);
        } else if (type == Double.class) {
            param = str2Double(v);
        } else if (type == Short.class) {
            param = str2Short(v);
        } else if (type == Boolean.class) {
            param = str2Boolean(v);
        } else if (Date.class.isAssignableFrom(type)) {
            param = str2Date(v);
        } else {
            throw new IllegalArgumentException(String.format("object type '%s' not valid", type));
        }
        return (T) param;
    }

    /**
     * Any -> Object[] <br>
     * <p>
     * obj == null					: 返回 Object[] {null} <br>
     * obj 为对象数组				: 强制转换为 Object[], 并返回自身 <br>
     * obj 为基础类型数组			: 返回 Object[], 其元素类型为基础类型的包装类 <br>
     * obj 为 {@link Collection}	: 通过 toArray() 方法返回 Object[] <br>
     * obj 为 {@link Iterable}		: 遍历 {@link Iterable}, 并返回包含其所有元素的 Object[] <br>
     * obj 为 {@link Iterator}		: 遍历 {@link Iterator}, 并返回包含其所有元素的 Object[] <br>
     * obj 为 {@link Enumeration}	: 遍历 {@link Enumeration}, 并返回包含其所有元素的 Object[] <br>
     * obj 为普通对象				: 返回 Object[] {obj} <br>
     *
     * @param obj : 任何对象
     */
    public static final Object[] object2Array(Object obj) {
        Object[] array;

        if (obj == null) {
            array = new Object[]{obj};
        } else if (obj.getClass().isArray()) {
            Class<?> clazz = obj.getClass().getComponentType();

            if (Object.class.isAssignableFrom(clazz)) {
                array = (Object[]) obj;
            } else {
                int length = Array.getLength(obj);

                if (length > 0) {
                    array = new Object[length];

                    for (int i = 0; i < length; i++) {
                        array[i] = Array.get(obj, i);
                    }
                } else {
                    array = new Object[0];
                }
            }
        } else if (obj instanceof Collection<?>) {
            array = ((Collection<?>) obj).toArray();
        } else if (obj instanceof Iterable<?>) {
            List<Object> list = new ArrayList<Object>();
            Iterator<?> it = ((Iterable<?>) obj).iterator();

            while (it.hasNext()) {
                list.add(it.next());
            }
            array = list.toArray();
        } else if (obj instanceof Iterator) {
            List<Object> list = new ArrayList<Object>();
            Iterator<?> it = (Iterator<?>) obj;

            while (it.hasNext()) {
                list.add(it.next());
            }
            array = list.toArray();
        } else if (obj instanceof Enumeration<?>) {
            List<Object> list = new ArrayList<Object>();
            Enumeration<?> it = (Enumeration<?>) obj;

            while (it.hasMoreElements()) {
                list.add(it.nextElement());
            }
            array = list.toArray();
        } else {
            array = new Object[]{obj};
        }
        return array;
    }

    /**
     * 返回 date 加上 value 天后的日期（清除时间信息）
     */
    public final static Date addDate(Date date, int value) {
        return addDate(date, value, true);
    }

    /**
     * 返回 date 加上 value 天后的日期，trimTime 指定是否清除时间信息
     */
    public final static Date addDate(Date date, int value, boolean trimTime) {
        return addTime(date, Calendar.DATE, value, trimTime);

    }

    /**
     * 返回 date 加上 value 个 field 时间单元后的日期（不清除时间信息）
     */
    public final static Date addTime(Date date, int field, int value) {
        return addTime(date, field, value, false);
    }

    public static String addTime(Date d, int day,String format) {
        Calendar calendar = getCalendar();
        calendar.setTime(d);
        calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + day);
        return date2Str(calendar.getTime(),format);
    }

    private static Calendar getCalendar(){
        return getCalendar("GMT+8");
    }

    private static Calendar getCalendar(String s) {
        Calendar c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone(s));
        return c;
    }

    /**
     * 返回 date 加上 value 个 field 时间单元后的日期，trimTime 指定是否去除时间信息
     */
    public final static Date addTime(Date date, int field, int value, boolean trimTime) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(field, value);

        if (trimTime) {
            c.set(Calendar.HOUR, 0);
            c.set(Calendar.MINUTE, 0);
            c.set(Calendar.SECOND, 0);
            c.set(Calendar.MILLISECOND, 0);
        }

        return c.getTime();

    }

    /**
     * java.util.Date -> String，str 的格式由 format  定义
     */
    public final static String date2Str(Date date, String format) {
        DateFormat df = new SimpleDateFormat(format);
        return df.format(date);
    }

    /**
     * 获取某天开始的时间戳
     * @param timeStamp 毫秒级时间戳
     * @param timeZone  如 GMT+8:00
     */
    public static Long getDailyStartTime(Long timeStamp, String timeZone) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }


    /**
     * 修整 SQL 语句字符串：' -> ''，（includeWidlcard 指定是否对星号和问号作转换：* -> %, ? -> _）
     */
    public static final String regularSQLStr(String str, boolean includeWidlcard) {
        str = str.replace("'", "''");

        if (includeWidlcard) {
            str = str.replace('*', '%');
            str = str.replace('?', '_');
        }

        return str;
    }

    /**
     * 获取 clazz 的 {@link ClassLoader} 对象，如果为 null 则返回当前线程的 Context {@link ClassLoader}
     */
    public static final ClassLoader getClassLoader(Class<?> clazz) {
        ClassLoader loader = clazz.getClassLoader();

        if (loader == null) {
            loader = Thread.currentThread().getContextClassLoader();
        }
        return loader;
    }


    /**
     * 用 {@linkplain Class#forName(String)} 加载 {@link Class} 对象，如果加载失败则返回 null
     */
    public static final Class<?> classForName(String name) {
        Class<?> clazz = null;

        try {
            clazz = Class.forName(name);
        } catch (ClassNotFoundException e) {

        }

        return clazz;
    }

    /**
     * 用 {@linkplain Class#forName(String, boolean, ClassLoader)} 加载 {@link Class} 对象，如果加载失败则返回 null
     */
    public static final Class<?> classForName(String name, boolean initialize, ClassLoader loader) {
        Class<?> clazz = null;

        try {
            clazz = Class.forName(name, initialize, loader);
        } catch (ClassNotFoundException e) {

        }

        return clazz;
    }

    /**
     * 获取 clazz 资源环境中 resPath 相对路径的 URL 对象
     */
    public static final URL getClassResource(Class<?> clazz, String resPath) {
        URL url = clazz.getResource(resPath);

        if (url == null) {
            ClassLoader loader = clazz.getClassLoader();
            if (loader != null) {
                url = loader.getResource(resPath);
            }
            if (url == null) {
                loader = Thread.currentThread().getContextClassLoader();
                if (loader != null) {
                    url = loader.getResource(resPath);
                }
            }
        }

        return url;
    }

    /**
     * 获取 clazz 资源环境中 resPath 相对路径的 URL 对象列表
     */
    public static final List<URL> getClassResources(Class<?> clazz, String resPath) {
        List<URL> urlList = new ArrayList<URL>();
        Enumeration<URL> urls = null;

        try {
            ClassLoader loader = clazz.getClassLoader();
            if (loader != null) {
                urls = loader.getResources(resPath);
            }

            if (urls == null || !urls.hasMoreElements()) {
                loader = Thread.currentThread().getContextClassLoader();
                if (loader != null) {
                    urls = loader.getResources(resPath);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        if (urls != null) {
            while (urls.hasMoreElements()) {
                urlList.add(urls.nextElement());
            }
        }

        return urlList;
    }

    /**
     * 获取 clazz 资源环境中 resPath 的 {@link InputStream}
     */
    public static final InputStream getClassResourceAsStream(Class<?> clazz, String resPath) {
        InputStream is = clazz.getResourceAsStream(resPath);

        if (is == null) {
            ClassLoader loader = clazz.getClassLoader();
            if (loader != null) {
                is = loader.getResourceAsStream(resPath);
            }

            if (is == null) {
                loader = Thread.currentThread().getContextClassLoader();
                if (loader != null) {
                    is = loader.getResourceAsStream(resPath);
                }
            }
        }

        return is;
    }

    /**
     * 获取 clazz 资源环境中 resPath 相对路径的 URL 绝对路径（返还的绝对路径用 UTF-8 编码）
     */
    public static final String getClassResourcePath(Class<?> clazz, String resPath) {
        return getClassResourcePath(clazz, resPath, DEFAULT_ENCODING);
    }

    /**
     * 获取 clazz 资源环境中 resPath 相对路径的 URL 绝对路径（返还的绝对路径用 pathEnc 编码）
     */
    public static final String getClassResourcePath(Class<?> clazz, String resPath, String pathEnc) {
        String path = null;

        try {
            URL url = getClassResource(clazz, resPath);

            if (url != null) {
                path = url.getPath();
                path = URLDecoder.decode(path, pathEnc);
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

        return path;
    }

    /**
     * 获取 clazz 资源环境中 resPath 相对路径的 URL 绝对路径列表（返还的绝对路径用 UTF-8 编码）
     */
    public static final List<String> getClassResourcePaths(Class<?> clazz, String resPath) {
        return getClassResourcePaths(clazz, resPath, DEFAULT_ENCODING);
    }

    /**
     * 获取 clazz 资源环境中 resPath 相对路径的 URL 绝对路径列表（返还的绝对路径用 pathEnc 编码）
     */
    public static final List<String> getClassResourcePaths(Class<?> clazz, String resPath, String pathEnc) {
        List<String> pathList = new ArrayList<String>();

        try {
            List<URL> urlList = getClassResources(clazz, resPath);

            for (URL url : urlList) {
                String path = URLDecoder.decode(url.getPath(), pathEnc);
                pathList.add(path);
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

        return pathList;
    }

    /**
     * 获取 clazz 资源环境的当前 URL 绝对路径（返回的绝对路径用 pathEnc 编码）
     */
    public static final String getClassPath(Class<?> clazz) {
        return getClassResourcePath(clazz, ".");
    }

    /**
     * 获取 resource 资源的 locale 本地化文件中名字为 key 的字符串资源，并代入 params 参数
     */
    public static final String getResourceMessage(Locale locale, String resource, String key, Object... params) {
        ResourceBundle bundle = ResourceBundle.getBundle(resource, locale);
        String msg = bundle.getString(key);

        if (params != null && params.length > 0) {
            msg = MessageFormat.format(msg, params);
        }
        return msg;
    }

    /**
     * 获取 resource 资源的默认本地化文件中名字为 key 的字符串资源，并代入 params 参数
     */
    public static final String getResourceMessage(String resource, String key, Object... params) {
        return getResourceMessage(Locale.getDefault(), resource, key, params);
    }

    /**
     * 获取 e 异常的堆栈信息，最大的堆栈层数由 levels 指定
     */
    public static final String getExceptionMessageStackString(Throwable e, int levels) {
        StringBuilder sb = new StringBuilder();

        if (levels == 0) {
            levels = Integer.MAX_VALUE;
        }
        for (int i = 0; i < levels; ++i) {
            if (i > 0) {
                sb.append("Caused by -> ");
            }
            sb.append(e.getClass().getName());

            String msg = e.getLocalizedMessage();
            if (msg != null) {
                sb.append(": ").append(msg);
            }

            e = e.getCause();
            if (e == null) {
                break;
            }
        }

        return sb.toString();
    }

    /**
     * 获取 e 异常的整个堆栈列表
     */
    public static final String getExceptionMessageStackString(Throwable e) {
        return getExceptionMessageStackString(e, 0);
    }

    /**
     * 获取 e 异常的堆栈列表，最大的堆栈层数由 levels 指定
     */
    public static final List<String> getExceptionMessageStack(Throwable e, int levels) {
        List<String> list = new ArrayList<String>();

        if (levels == 0) {
            levels = Integer.MAX_VALUE;
        }
        for (int i = 0; i < levels; ++i) {
            StringBuilder sb = new StringBuilder();

            if (i > 0) {
                sb.append("Caused by -> ");
            }
            sb.append(e.getClass().getName());

            String msg = e.getLocalizedMessage();
            if (msg != null) {
                sb.append(": ").append(msg);
            }

            list.add(sb.toString());

            e = e.getCause();
            if (e == null) {
                break;
            }
        }

        return list;
    }

    /**
     * 获取 e 异常的整个堆栈列表
     */
    public static final List<String> getExceptionMessageStack(Throwable e) {
        return getExceptionMessageStack(e, 0);
    }

    /**
     * 输出 e 异常的 levels 层堆栈列表到 ps 中
     */
    public static final void printExceptionMessageStack(Throwable e, int levels, PrintStream ps) {
        List<String> list = getExceptionMessageStack(e, levels);

        for (String msg : list) {
            ps.println(msg);
        }
    }

    /**
     * 输出 e 异常的 levels 层堆栈列表到标准错误流中
     */
    public static final void printExceptionMessageStack(Throwable e, int levels) {
        printExceptionMessageStack(e, levels, System.err);
    }

    /**
     * 输出 e 异常的整个堆栈列表到 ps 中
     */
    public static final void printExceptionMessageStack(Throwable e, PrintStream ps) {
        printExceptionMessageStack(e, 0, ps);
    }

    /**
     * 输出 e 异常的整个堆栈列表到标准错误流中
     */
    public static final void printExceptionMessageStack(Throwable e) {
        printExceptionMessageStack(e, 0);
    }

    /**
     * 把元素添加到 {@link Map} 中，不保证线程安全（不替换原值）
     */
    public static final <K, V> boolean tryPut(Map<K, V> map, K key, V value) {
        return tryPut(map, key, value, false);
    }

    /**
     * 把元素添加到 {@link Map} 中，不保证线程安全
     */
    public static final <K, V> boolean tryPut(Map<K, V> map, K key, V value, boolean replace) {
        if (replace || !map.containsKey(key)) {
            map.put(key, value);
            return true;
        }

        return false;
    }

    /**
     * 把元素添加到 {@link Map} 中，并保证线程安全（不替换原值）
     */
    public static final <K, V> boolean syncTryPut(Map<K, V> map, K key, V value) {
        return syncTryPut(map, key, value, false);
    }

    /**
     * 把元素添加到 {@link Map} 中，并保证线程安全
     */
    public static final <K, V> boolean syncTryPut(Map<K, V> map, K key, V value, boolean replace) {
        synchronized (map) {
            return tryPut(map, key, value, replace);
        }
    }

    /**
     * 把元素添加到 {@link Map} 中，不保证线程安全（不替换原值）
     */
    public static final <K, V> int tryPutAll(Map<K, V> map, Map<K, V> src) {
        return tryPutAll(map, src, false);
    }

    /**
     * 把元素添加到 {@link Map} 中，不保证线程安全
     */
    public static final <K, V> int tryPutAll(Map<K, V> map, Map<K, V> src, boolean replace) {
        if (replace) {
            map.putAll(src);
            return src.size();
        }

        int count = 0;
        Set<Map.Entry<K, V>> entries = src.entrySet();

        for (Map.Entry<K, V> e : entries) {
            if (!map.containsKey(e.getKey())) {
                map.put(e.getKey(), e.getValue());
                ++count;
            }
        }

        return count;
    }

    /**
     * 把元素添加到 {@link Map} 中，并保证线程安全（不替换原值）
     */
    public static final <K, V> int syncTryPutAll(Map<K, V> map, Map<K, V> src) {
        return syncTryPutAll(map, src, false);
    }

    /**
     * 把元素添加到 {@link Map} 中，并保证线程安全
     */
    public static final <K, V> int syncTryPutAll(Map<K, V> map, Map<K, V> src, boolean replace) {
        synchronized (map) {
            return tryPutAll(map, src, replace);
        }
    }

    /**
     * 从 {@link Map} 中删除元素，不保证线程安全
     */
    public static final <K, V> boolean tryRemove(Map<K, V> map, K key) {
        if (map.containsKey(key)) {
            map.remove(key);
            return true;
        }

        return false;
    }

    /**
     * 从 {@link Map} 中删除元素，并保证线程安全
     */
    public static final <K, V> boolean syncTryRemove(Map<K, V> map, K key) {
        synchronized (map) {
            return tryRemove(map, key);
        }
    }

    /**
     * 清空 {@link Map}，不保证线程安全
     */
    public static final <K, V> void tryClear(Map<K, V> map) {
        map.clear();
    }

    /**
     * 清空 {@link Map}，并保证线程安全
     */
    public static final <K, V> void syncTryClear(Map<K, V> map) {
        synchronized (map) {
            tryClear(map);
        }
    }

    /**
     * 获取当前 JVM 进程的 ID
     */
    public static final int getProcessId() {
        return Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
    }

    /**
     * 获取当前 JVM 进程的 Java 版本
     */
    public static final String getJavaVersion() {
        return System.getProperty("java.version");
    }

    /**
     * 获取当前操作系统的名称
     */
    public static final String getOSName() {
        return System.getProperty("os.name");
    }

    /**
     * 检查当前操作系统是否为 Windows 系列
     */
    public static final boolean isWindowsPlatform() {
        // return CURRENT_OS.toUpperCase().indexOf("WINDOWS") != -1;

        return File.pathSeparatorChar == ';';
    }

    public static final String randomStr(int length) {
        return RandomStringUtils.randomAlphabetic(length);
    }

    /**
     * 按拼音排序的字符串比较器
     */
    public static class PinYinComparator implements Comparator<String> {
        @Override
        public int compare(String o1, String o2) {
            java.text.Collator cmp = java.text.Collator.getInstance(Locale.CHINA);
            return cmp.compare(o1, o2);
        }
    }







    /**
     * 时间戳转日期格式
     * @param timeStamp 时间戳(精确到秒)
     * @param format 日期格式
     * @return
     */
    public static String timeStamptoStr(String timeStamp,String format){

        if (timeStamp == null || timeStamp.isEmpty() || timeStamp.equals("null")) {
            return "";
        }
        if (format == null || format.isEmpty()) {
            format = "yyyy-MM-dd HH:mm:ss";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date time = new Date(Long.valueOf(timeStamp)*1000);
        return sdf.format(time);
    }

    public static <T> T copyProperties(Class<T> tClass, Map<String, Object> map){
        return JSON.parseObject(JSON.toJSONString(map), tClass);
    }

    public static <T> T copyProperties(Class<T> tClass, Object object){
        return JSON.parseObject(JSON.toJSONString(object), tClass);
    }
}
